/**
 * 
 */
package org.jackysoft.data;

import java.io.Serializable;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jackysoft.entity.Identifiable;
import org.jackysoft.util.Page;

import com.google.common.collect.Maps;

/**
 * @author Ernesto Reinaldo Barreiro (reirn70@gmail.com)
 * 
 */
public class ProviderNavigator<B extends Identifiable> implements Serializable {
	private final Log logger = LogFactory.getLog(ProviderNavigator.class);

	private static final long serialVersionUID = 1L;

	private IDataProvider<?, B> dataProvider;

	private TransferProtocol protocol;

	private Map<String, Object> searchMap = Maps.newHashMap();

	private SortInfo sortInfo;

	private int page;
	private int rows;
	private String sord;
	private String sidx;
	private boolean listAll;

	public ProviderNavigator(IDataProvider<?, B> dataProvider,
			TransferProtocol proto, Map<String, Object> smap) {
		this.protocol = proto;
		this.dataProvider = dataProvider;
		this.searchMap = smap;
	}

	/**
	 * 
	 * @param request
	 * @return
	 */
	public final Page renderData() throws Exception {
		configureSort();
		switch (this.getProtocol()) {
		case xml:
			return renderXML();
		case json:
			return renderJson();
		case pojo:
			return renderPojo();
		default:
			return renderPojo();
		}
	}

	/**
	 * Give a chance to configure the provider.
	 * 
	 * @param dataProvider
	 */
	protected void configureSort() {
		SortOrder sortOrder = getSortOrder();
		String propertyPath = getSortColumn();
		if (propertyPath != null) {
			this.sortInfo = new SortInfo(propertyPath, sortOrder);
		} else {
			this.sortInfo = null;
		}
	}

	protected Page renderJson() throws Exception {
		Page pager = new Page();

		if (listAll) {
			Iterable<? extends B> it = getRows(0, 0, null, null);
			pager.setRows(it);
			return pager;
		}

		int rows = getNumberOfRows();
		int page = getCurrentPage();
		int records = totalRecords(this.sortInfo, this.searchMap);
		int start = rows * (page - 1);
		pager.setPage(page);
		pager.setRecords(records);
		Iterable<? extends B> it = getRows(start, rows, sortInfo, searchMap);
		pager.setRows(it);
		return pager;
	}

	protected Page renderPojo() throws Exception {
		Page pager = new Page();
		
		int rows = getNumberOfRows();
		int page = getCurrentPage();
		int records = totalRecords(this.sortInfo, this.searchMap);
		int start = rows * (page - 1);
		pager.setPage(page);
		pager.setRecords(records);
		Iterable<? extends B> it = getRows(start, rows, sortInfo, searchMap);
		pager.setRows(it);
		return pager;
	}

	/**
	 * 
	 * @param request
	 * @return
	 */
	protected Page renderXML() throws Exception {
		return new Page();
	}

	private Iterable<? extends B> getRows(int start, int rows,
			SortInfo sortInfo, Map<String, Object> smap) {
		return this.dataProvider.getData(start, rows, listAll, sortInfo, smap);
	}

	private int totalRecords(SortInfo sortInfo, Map<String, Object> smap) {
		return this.dataProvider.getSize(sortInfo, smap);
	}

	private int getCurrentPage() {
		try {
			return page;
		} catch (Exception e) {
			return 10;
		}
	}

	private int getNumberOfRows() {
		try {
			return rows;
		} catch (Exception e) {
			return 10;
		}
	}

	private SortOrder getSortOrder() {
		try {
			return SortOrder.valueOf(getSord());
		} catch (Exception e) {
			return SortOrder.asc;
		}
	}

	private String getSortColumn() {
		try {
			return sidx;
		} catch (Exception e) {
			return null;
		}
	}

	public TransferProtocol getProtocol() {
		return protocol;
	}

	public void setProtocol(TransferProtocol protocol) {
		this.protocol = protocol;
	}

	/**
	 * 返回页号
	 * */
	public int getPage() {
		return page;
	}

	public void setPage(int page) {
		this.page = page;
	}

	/**
	 * 返回每页显示数量
	 * */
	public int getRows() {
		return rows;
	}

	public void setRows(int rows) {
		this.rows = rows;
	}

	/**
	 * 返回排序方式
	 * */
	public String getSord() {
		return sord;
	}

	public void setSord(String sord) {
		this.sord = sord;
	}

	/** 返回排序列名称 */
	public String getSidx() {
		return sidx;
	}

	public void setSidx(String sidx) {
		this.sidx = sidx;
	}

	public void setListAll(boolean listAll) {
		this.listAll = listAll;
	}

	public boolean isListAll() {
		return listAll;
	}
}
